window.addEventListener('DOMContentLoaded', function () {
	// 常量 一个块的宽高
	const constant = 20;
	// 常量 容器行列数
	const rowCount = 23,
		colCount = 15;
	// 定义16宫格的位置
	let locationX = 0,
		locationY = 0;
	// 定时器
	let timer = null;
	let time = 1000;
	// 右侧提示模型数据源序号
	let reminder = null;
	// 分数初始值
	let grade = 0;
	// 模型生成个数初始值
	let generateNum = 0;
	// 记录难度初始值
	let difficulty = 0;
	// 创建模型数据源---------------------------模型数据-------------------------------
	let MODELS = [
		// L型模型
		{
			0: {
				row: 2,
				col: 0,
			},
			1: {
				row: 2,
				col: 1,
			},
			2: {
				row: 2,
				col: 2,
			},
			3: {
				row: 1,
				col: 2,
			},
		},
		// Z型模型
		{
			0: {
				row: 1,
				col: 1,
			},
			1: {
				row: 1,
				col: 2,
			},
			2: {
				row: 2,
				col: 2,
			},
			3: {
				row: 2,
				col: 3,
			},
		},
		// I型模型
		{
			0: {
				row: 0,
				col: 1,
			},
			1: {
				row: 1,
				col: 1,
			},
			2: {
				row: 2,
				col: 1,
			},
			3: {
				row: 3,
				col: 1,
			},
		},
		// O型模型
		{
			0: {
				row: 1,
				col: 1,
			},
			1: {
				row: 2,
				col: 1,
			},
			2: {
				row: 1,
				col: 2,
			},
			3: {
				row: 2,
				col: 2,
			},
		},
		// T型模型
		{
			0: {
				row: 2,
				col: 0,
			},
			1: {
				row: 2,
				col: 1,
			},
			2: {
				row: 2,
				col: 2,
			},
			3: {
				row: 1,
				col: 1,
			},
		},
		// S型模型
		{
			0: {
				row: 2,
				col: 0,
			},
			1: {
				row: 2,
				col: 1,
			},
			2: {
				row: 1,
				col: 1,
			},
			3: {
				row: 1,
				col: 2,
			},
		},
		// J型模型
		{
			0: {
				row: 1,
				col: 0,
			},
			1: {
				row: 2,
				col: 0,
			},
			2: {
				row: 2,
				col: 1,
			},
			3: {
				row: 2,
				col: 2,
			},
		},
	];

	// 创建随机颜色
	let colorBlock = [
		'rgb(158,46,36)',
		'rgb(226,175,66)',
		'rgb(64,125,82)',
		'rgb(207,182,74)',
		'rgb(154,180,205)',
		'rgb(142,41,97)',
	];
	// 模型颜色数据源序号
	let randomColor = null;
	// 当前模型的颜色
	let currentColor = null;
	// rgb 颜色(参数赋值给randomColor)
	let nextColor = null;

	// 当前使用的模型
	let currentModel = null;
	// 下次使用的模型
	let nextModelBlock = null;

	// 记录所有模型的位置
	// 存储方式 (行)/(列) = 值
	let locationModel = {};

	// 初始化
	function init() {
		onKeyDown();
		creationModel();
		score();
	}
	// init();
	startTheGame();

	// 开始游戏按钮
	function startTheGame() {
		let btn = document.querySelector('.btn');
		let presentScore = document.querySelector('.presentScore');
		let quantity = document.querySelector('.quantity');
		let btn_box = document.querySelector('.btn_box');
		btn.addEventListener('mousedown', function () {
			// 鼠标按下时进行视觉反馈---------改变按钮颜色
			this.style.backgroundColor = 'rgb(200,200,200)';
			// 鼠标抬起时开始游戏
			btn.addEventListener('mouseup', function () {
				// 引入键盘事件
				onKeyDown();
				// 初始化分数
				score();
				// 创建模型
				creationModel();
				btn_box.style.display = 'block';
				presentScore.style.display = 'block';
				quantity.style.display = 'block';
			});
		});
	}

	// 生成随机数(随机生成模型)
	function getRandomIntInclusive(min, max) {
		min = Math.ceil(min);
		max = Math.floor(max);
		return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值，含最小值
	}

	// 创建无定义位置模型---------------------------核心函数---------------------------------
	function creationModel() {
		// 当检测到第0行存在元素时结束游戏
		if (gameOver()) {
			// 停止定时器
			isGameOver();
			return;
		}
		let gameScreen = document.querySelector('.gameScreen');
		// 游戏开始时组建的第一个模型
		let random = getRandomIntInclusive(0, MODELS.length - 1);
		// 当前定义的模型
		// if (reminder) {
		// 	currentModel = nextModelBlock;
		// } else {
		// 	currentModel = MODELS[random];
		// }
		// 当reminder为空时使用random的随机数
		currentModel =
			reminder === null ? (currentModel = MODELS[random]) : (currentModel = nextModelBlock);
		// 生成游戏窗口模型后随机生成一个数(用于提示窗口展示模型)
		reminder = getRandomIntInclusive(0, MODELS.length - 1);
		// 游戏开始时组建的第一个模型的颜色
		let randomColorFirst = getRandomIntInclusive(0, colorBlock.length - 1);
		// 当randomColor为空时使用randomColorFirst的随机数
		currentColor =
			randomColor === null
				? (currentColor = colorBlock[randomColorFirst])
				: (currentColor = nextColor);
		// 生成游戏窗口模型颜色后随机生成一个数
		randomColor = getRandomIntInclusive(0, colorBlock.length - 1);
		// 生成模型前重新定义16宫格的位置(使生成的模型在游戏窗口居顶并居中)
		locationX = 6;
		locationY = 0;
		for (const key in currentModel) {
			// 创建单个盒子模型
			let blockModel = document.createElement('div');
			// 给每个盒子添加类名
			blockModel.className = 'activityBlock';
			blockModel.style.backgroundColor = currentColor;
			// 写入到游戏窗口
			gameScreen.appendChild(blockModel);
		}
		// 展示下一个模型前清除上次展示的模型
		showBlock();
		// 展示下一个模型
		nextModel();
		// 计算模型生成的个数
		generate();
		// 确定元素位置
		locationBlock();
		// 定时器 使模型自动下落
		selfActing();
		// 游戏难度随产生模型的数量增加而增加(难度:增加下落速度)
		addDifficulty();
	}

	// 根据数据源定位元素的位置
	function locationBlock() {
		// 判断模型是否超出游戏可视窗口
		restrictedArea();
		// 获取已生成的无定义位置的模型
		let ele = document.querySelectorAll('.activityBlock');
		for (let i = 0; i < ele.length; i++) {
			// 单个对应元素
			let modelEle = ele[i];
			// 单个对应数据
			let singleBlock = currentModel[i];
			// 将数据导入到对应元素
			// 16宫格的位置加上元素在十六宫格的位置
			modelEle.style.top = (locationY + singleBlock.row) * constant + 'px';
			modelEle.style.left = (locationX + singleBlock.col) * constant + 'px';
		}
	}

	// 监听用户键盘事件
	function onKeyDown() {
		document.addEventListener('keydown', function (event) {
			switch (event.key) {
				case 'w':
					// move(0, -1);
					rotateModel();
					break;
				case 's' || 'ArrowDown':
					move(0, 1);
					break;
				case 'a' || 'ArrowLeft':
					move(-1, 0);
					break;
				case 'd' || 'ArrowRight':
					move(1, 0);
					break;
				case 'ArrowUp':
					rotateModel();
					break;
				case 'ArrowDown':
					move(0, 1);
					break;
				case 'ArrowLeft':
					move(-1, 0);
					break;
				case 'ArrowRight':
					move(1, 0);
					break;
				default:
					break;
			}
		});
	}

	// 控制方块移动
	function move(x, y) {
		// 使16宫格移动(自增)
		if (touchModel(locationX + x, locationY + y, currentModel)) {
			// 当底部碰撞时将该模型变色并固定在该位置
			if (y !== 0) {
				fixedModel();
			}
			return;
		}
		locationX += x;
		locationY += y;
		locationBlock();
	}

	// 旋转模型
	function rotateModel() {
		// 旋转后的行 = 旋转前的列;
		// 旋转后的列 = 3 - 旋转前的行;
		for (const key in currentModel) {
			let serialNumber = currentModel[key];
			let temp = serialNumber.row;
			serialNumber.row = serialNumber.col;
			serialNumber.col = 3 - temp;
			// 垃圾回收
			temp = null;
		}

		// 判断模型旋转时是否碰撞模型
		let newObj = {};
		// 深拷贝
		for (const key in currentModel) {
			newObj[key] = currentModel[key];
		}
		if (touchModel(locationX, locationY, newObj)) {
			return;
		}
		currentModel = newObj;
		locationBlock();
	}

	// 限制模型移动区域
	function restrictedArea() {
		// 16宫格移动最大距离
		let maxLeft = 0,
			maxRight = colCount,
			maxBottom = rowCount;
		for (const key in currentModel) {
			let distance = currentModel[key];
			// maxLeft
			if (locationX + distance.col < maxLeft) {
				locationX++;
			} else if (locationX + distance.col >= maxRight) {
				locationX--;
			} else if (locationY + distance.row >= maxBottom) {
				locationY--;
				fixedModel();
			}
		}
	}

	// 使模型固定在底部
	function fixedModel() {
		// 获取在需固定在底部的模型
		let boxModel = document.querySelectorAll('.activityBlock');
		// 改变模型的样式并使模型不可移动
		// 修改类名
		for (let i = 0; i < boxModel.length; i++) {
			boxModel[i].className = 'fixedBlock';
			// 记录当前块 证明该位置已存在块元素
			let oneBlock = currentModel[i];
			locationModel[locationY + oneBlock.row + '/' + (locationX + oneBlock.col)] = boxModel[i];
		}
		// 计算得分
		grade++;
		score();
		// 判断是否有某行铺满
		isRemoveLine();
		// 重新生成模型
		creationModel();
	}

	// 判断模型与模型之间是否碰撞
	function touchModel(x, y, model) {
		for (const key in model) {
			let newModel = model[key];
			if (locationModel[y + newModel.row + '/' + (x + newModel.col)]) {
				return true;
			}
		}
		return false;
	}

	// 判断是否有某行铺满
	function isRemoveLine() {
		for (let i = 0; i < rowCount; i++) {
			let flag = true;
			for (let j = 0; j < colCount; j++) {
				if (!locationModel[i + '/' + j]) {
					flag = false;
					break;
				}
			}
			// 当flag为true时则一行铺满
			if (flag) {
				// 传递行号 清除该行
				removeLine(i);
			}
		}
	}

	// 清理铺满的一行
	function removeLine(clear) {
		for (let i = 0; i < colCount; i++) {
			let gameScreen = document.querySelector('.gameScreen');
			// 清除元素
			gameScreen.removeChild(locationModel[clear + '/' + i]);
			// 清除被清理元素的数据源
			// 垃圾回收
			locationModel[clear + '/' + i] = null;
		}
		downFall(clear);
	}

	// 清理铺满的行后使没铺满的模型下落
	function downFall(line) {
		for (let i = line; i > 0; i--) {
			for (let j = 0; j < colCount; j++) {
				if (!locationModel[i + '/' + j]) {
					continue;
				}
				locationModel[i + 1 + '/' + j] = locationModel[i + '/' + j];
				locationModel[i + 1 + '/' + j].style.top = (i + 1) * constant + 'px';
				locationModel[i + '/' + j] = null;
			}
		}
	}

	// 使模型自动下落
	function selfActing() {
		// 如果已经存在定时器 则清除上个定时器
		if (timer) {
			clearInterval(timer);
		}
		timer = setInterval(() => {
			move(0, 1);
		}, time);
	}

	// 计算得分
	function score() {
		let span = document.querySelector('.presentScore p span');
		span.innerHTML = grade;
	}

	// 计算模型生成的个数
	function generate() {
		let span = document.querySelector('.quantity p span');
		generateNum++;
		// difficulty : 难度计数
		difficulty++;
		span.innerHTML = generateNum;
	}

	// 模型下落速度及得分数产生的模型数量增加而增加
	function addDifficulty() {
		// 每产生20个模型 下落速度增加10毫秒
		if (difficulty === 20) {
			time -= 10;
			difficulty = 0;
		}
		// setInterval(() => {
		// 	time -= 10;
		// 	grade += 1;
		// }, 3000);
	}

	/**
	 * *右侧提示下一个模型
	 * 游戏开始
	 * 游戏窗口组建模型后调用一次随机数 变量名为num
	 * 取得num值给提示模块 提示模块接收值后组件模型 出现模型
	 * 当游戏窗口模型固定后 从num取值 并重新组建模型给游戏窗口
	 * 当游戏窗口重新组建新模型后 再调用一次随机数 并把值传递给num
	 * 提示窗口组件模型前把上一次提示的模型清除
	 */
	function nextModel() {
		let show = document.querySelector('.show');
		// 获取游戏窗口组建模型后定义的模型值
		nextModelBlock = MODELS[reminder];
		// 获取游戏窗口组件后定义的颜色值
		nextColor = colorBlock[randomColor];
		// 根据值组件模型
		for (const key in nextModelBlock) {
			// 创建单个盒子模型
			let blockModel = document.createElement('div');
			// 给每个盒子添加类名
			blockModel.className = 'showBlock';
			// 提示窗口模型颜色
			blockModel.style.backgroundColor = nextColor;
			// 写入到游戏窗口
			show.appendChild(blockModel);
		}
		// 根据数据布局模型
		let ele = document.querySelectorAll('.showBlock');
		for (let i = 0; i < ele.length; i++) {
			// 单个对应元素
			let modelEle = ele[i];
			// 单个对应数据
			let singleBlock = nextModelBlock[i];
			// 将数据导入到对应元素
			// 16宫格的位置加上元素在十六宫格的位置
			modelEle.style.top = (2.2 + singleBlock.row) * constant + 'px';
			modelEle.style.left = (2.2 + singleBlock.col) * constant + 'px';
		}
	}

	// 清除展示区的模型
	function showBlock() {
		let show = document.querySelector('.show');
		let ele = document.querySelectorAll('.showBlock');
		for (let i = 0; i < ele.length; i++) {
			show.removeChild(ele[i]);
		}
	}

	// 判断游戏是否结束
	function gameOver() {
		// 当第0行存在元素时返回true
		for (let i = 0; i < colCount; i++) {
			if (locationModel['2/' + i]) {
				return true;
			}
		}
		return false;
	}

	// 结束游戏
	function isGameOver() {
		if (timer) {
			clearInterval(timer);
		}
		alert('123');
	}
});
